package org

import (
    "crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
	"time"
	"strconv"
	"dhfshop/models"
	"dhfshop/models/misc"
	"dhfshop/models/consts"
	"github.com/astaxie/beego/orm"
	//"github.com/astaxie/beego"
	"github.com/satori/go.uuid"
	"wxsdk/oauth"
)

type User struct {
    UserId          int64     `orm:"column(user_id);pk" json:"user_id" form:"user_id"`
	PartnerId       int64     `orm:"column(partner_id);index" json:"partner_id" form:"partner_id"`  //全都隶属于大黄蜂商城后台管理小程序这个组织
	UserName        string    `orm:"column(user_name);unique;size(45)" json:"user_name" form:"user_name"`
	Password        string    `orm:"-" json:"-" form:"password"`
	PasswordConfirm string    `orm:"-" json:"-" form:"password_confirm"`
	PasswordHashed  string    `orm:"column(password_hashed)" json:"-"`
	Salt            string    `orm:"column(salt)" json:"-"`
	Mobile          string    `orm:"null;column(mobile)" json:"mobile,omitempty" form:"mobile"`
	Avatar          string    `orm:"null;column(avatar)" json:"avatar" form:"avatar"`
	Email           string    `orm:"null;column(email)" json:"email,omitempty" form:"email"`
	Activated       bool      `orm:"column(activated)" json:"activated" form:"activated"` //1=激活,0=停用
	RoleIds         string    `orm:"column(role_ids);type(text)" json:"role_ids" form:"role_ids"`  //逗号分隔,以实现多对多
	Role            *Role     `orm:"-" json:"role,omitempty"`
	// 微信登陆用户信息
	FollowAppId     string   `orm:"column(follow_app_id)" json:"follow_app_id"`  //大黄蜂商城的后台管理账号，不是组织自己的
	OpenID          string   `orm:"column(open_id);size(190);index" json:"open_id"`        //关注大黄蜂商城后台管理小程序后产生的，全平台唯一
	NickName        string   `orm:"column(nick_name)" json:"nick_name"`    //
	Country         string   `orm:"column(country)" json:"country"`       //国家
	Province        string   `orm:"column(province)" json:"province"`     //省
	City            string   `orm:"column(city)" json:"city"`             //城市
	Unionid         string   `orm:"column(unionid)" json:"unionid"` //相同开发账号下多个公众号的用户唯一ID
    SessionKey      string   `orm:"column(session_key)" json:"session_key"` //
	CreatedAt       time.Time `orm:"auto_now_add;type(datetime);column(created_at)" json:"-" form:"-"`     
	UpdatedAt       time.Time `orm:"auto_now;type(datetime);column(updated_at)" json:"-" form:"-"`  
    CreatedAtStr    string    `orm:"-" json:"created_at"`
    UpdatedAtStr    string    `orm:"-" json:"updated_at"`
	//
	Proportion      int       `orm:"column(proportion);default(10)" json:"proportion" form:"proportion"` //返点比例,缺省10%
	RefUserId       int64     `orm:"column(ref_user_id);default(0)" json:"ref_user_id" form:"ref_user_id"`
	IsOpenApi       int       `orm:"column(is_openapi);default(0)" json:"is_openapi" form:"is_openapi"`  
}


func init() {
	orm.RegisterModel(new(User))
}

// 对用户密码进行加“盐”的加密处理
func EncryptPassword(salt, password string) string {
	h := hmac.New(sha1.New, []byte(salt))
	h.Write([]byte(password))
	return hex.EncodeToString(h.Sum(nil))
}

func UpdateUsersById(m *User,param ... string) (err error) {
	o := models.GetDefaultDB()
	v := User{UserId: m.UserId}
	if err = o.Read(&v); err == nil {
		if _, err = o.Update(m, param...); err == nil {
		   return 	
		}
	}
	return
}

func UpdateUsersByOpenId(m *User, param ... string) (err error) {
	o := models.GetDefaultDB()
	v := User{OpenID: m.OpenID}
	if err = o.Read(&v, "OpenID"); err == nil {
		m.UserId = v.UserId
		if _, err = o.Update(m, param...); err == nil {
		   return 	
		}
	}
	return
}

func DeleteUsers(user_id int64) (err error) {
	o := models.GetDefaultDB()
	v := User{UserId: user_id}
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&v); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}

// 根据用户名获取用户信息,用于账号密码登陆
// 如果没有记录，则返回：err: no row found
func GetUserByUsername(username string) (user *User, err error) {
	o := models.GetDefaultDB()
	user = &User{UserName:username}   //多个的话,read中需要指明列
	if err = o.Read(user,"Username"); err != nil {
		return user, err
	}
	return user, nil
}

func GetUserByUserId(uid int64) (user *User, err error) {
	o := models.GetDefaultDB()
	user = &User{UserId:uid}  
	if err = o.Read(user); err != nil {
		user.CreatedAtStr = user.CreatedAt.Format(consts.DATETIME_FORMAT)
        user.UpdatedAtStr = user.UpdatedAt.Format(consts.DATETIME_FORMAT)
		return user, err
	}
	return
}

func GetUserIdByOpenId(openId string) (user *User, err error) {
	o := models.GetDefaultDB()
	user = &User{OpenID:openId}   //多个的话,read中需要指明列
	if err = o.Read(user,"OpenID"); err != nil {
		return
	}
	return
}

func GetUserIdByOpenIdOrUserId(openId, userIdStr string) (user *User, err error) {
	user = &User{}
	o := models.GetDefaultDB()
	qs := o.QueryTable(new(User))
	if len(openId) > 0 {
	   qs = qs.Filter("open_id", openId)
	}
	if len(userIdStr) > 0 {
	   if userId, err := strconv.ParseInt(userIdStr, 10, 64); err == nil {
	       qs = qs.Filter("user_id", userId)
	   }
	}
	if err = qs.One(user); err == nil {
		return user, nil
	}
	return nil, err 
}

func GetUserIdByUnionid(unionid string) (user *User, err error) {
	o := models.GetDefaultDB()
	user = &User{Unionid:unionid}   //多个的话,read中需要指明列
	if err = o.Read(user,"Unionid"); err != nil {
		return
	}
	return
}

//创建超级管理员
func CreateAdminUser(user *User) (user_id int64, err error) {
	user.Salt = uuid.NewV4().String()
	if user.Password == "" {
		user.Password = strings.ToLower(user.UserName)
	}
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	o := models.GetDefaultDB()
	i, err := o.Insert(user)
	user_id = i
	return
}

// 创建用户信息
func CreateUser(user *User) (int64, error) {
	user.Salt = uuid.NewV4().String()
	if user.Password == "" {
		user.Password = strings.ToLower(user.UserName)
	}
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	user.Activated = false
	o := models.GetDefaultDB()
	i, err := o.Insert(user)
	return i, err
}

// 创建微信会员
func CreateWeChatUser(partnerId int64, roleIds string,weChatUser *oauth.BuyerUserInfo,refUserId int64) (user *User, err error) {
	user = new(User)
	user.PartnerId = partnerId
	user.RoleIds = roleIds
	user.UserId, _ = misc.GetUserNo()
	user.UserName = weChatUser.OpenID
	user.Password = strings.ToLower(weChatUser.OpenID)
	user.Salt = uuid.NewV4().String()
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	user.Activated = true
	user.FollowAppId = weChatUser.WaterMark.AppID
	user.OpenID = weChatUser.OpenID
	user.NickName = weChatUser.Nickname
	user.Province = weChatUser.Province
	user.City = weChatUser.City
	user.Country = weChatUser.Country
	user.Avatar = weChatUser.AvatarURL
	user.Unionid = weChatUser.Unionid
	user.SessionKey = weChatUser.SessionKey
	if refUserId > 0 {
	   user.RefUserId = refUserId
	}
	o := models.GetDefaultDB()
	_, err = o.Insert(user)
	return
}

func CreateBasicWeChatUser(partnerId int64,appID,roleIds string,weChatUser *oauth.SessionInfo,refUserId int64) (user *User, err error) {
	user = new(User)
	user.PartnerId = partnerId
	user.RoleIds = roleIds
	user.UserId, _ = misc.GetUserNo()
	user.UserName = weChatUser.OpenId
	user.Password = strings.ToLower(weChatUser.OpenId)
	user.Salt = uuid.NewV4().String()
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	user.Activated = true
	user.FollowAppId = appID
	user.OpenID = weChatUser.OpenId
	user.Unionid = weChatUser.UnionId
	user.SessionKey = weChatUser.SessionKey
	if refUserId > 0 {
	   user.RefUserId = refUserId
	}
	o := models.GetDefaultDB()
	_, err = o.Insert(user)
	return
}

//更新用户密码
func UpdateUserPasswd(user *User) (err error) {
	if len(user.Password) == 0 {
		return nil
	}
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	o := models.GetDefaultDB()
	_, err = o.Update(user, "password_hashed")
	return
}

// 重置用户密码为店铺的默认密码
func ResetUserPassword(userId int64) error {
	/*
	o := models.GetDefaultDB()
	user := &User{UserId: userId}
	if err := o.Read(user); err != nil {
		return err
	}
	shop, err := GetPartnerById(user.PartnerId)
	if err != nil {
		return err
	}
	user.Password = shop.DefaultPwd
	user.PasswordHashed = EncryptPassword(user.Salt, user.Password)
	_, err = o.Update(user, "password_hashed")
	return err
	*/
	return nil
}

func InitDefaultUser(partnerId int64,name string,password string,roleId,refUserId int64) (int64, error) {
	uid, _ := misc.GetUserNo()
	role, _:= GetRoleByRoleId(roleId)
	user := User{PartnerId:partnerId, UserId:uid,UserName:name,Password:password,Activated:true,Role:role}
	if refUserId > 0 {
	   user.RefUserId = refUserId
	}
	_ ,err := CreateAdminUser(&user)
	if err != nil {
	    return 0, err
	}
	return uid, nil
}

func GetAllUsers(query map[string]string, fields []string, order_by map[string]string, 
    offset int, limit int) ([]*User, int64,error) {
	o := models.GetDefaultDB()
	qs := o.QueryTable(new(User))
	for k, v := range query {
		k = strings.Replace(k, ".", "__", -1)
		qs = qs.Filter(k, v)
	}
	cnt, err := qs.Count()
	// order by:
	var sortFields []string
	for k, v := range order_by {
		orderby := ""
		if v == "desc" {
			orderby = "-" + k
		} else if v == "asc" {
			orderby = k
		} else {
			return nil, 0, errors.New("Error: Invalid order. Must be either [asc|desc]")
		}
		sortFields = append(sortFields, orderby)
	}
	qs = qs.OrderBy(sortFields...)
	var lists []*User
	if _, err := qs.Limit(limit, offset).All(&lists, fields...); err == nil {
	    for _, user := range lists {
			user.CreatedAtStr = user.CreatedAt.Format(consts.DATETIME_FORMAT)
            user.UpdatedAtStr = user.UpdatedAt.Format(consts.DATETIME_FORMAT)
	    }
		return lists, cnt, nil
	}
	return nil, 0, err
}

//启用、停用用户,更新缓存
func ActivedUser(partnerId, userId int, activated bool) (err error) {
    o := models.GetDefaultDB()
	if partnerId > 0 {
	    _, err = o.QueryTable(new(User)).Filter("partner_id", partnerId).Filter("user_id", userId).Update(
			orm.Params{
				"activated": activated,
			},
		)
	} else {
		_, err = o.QueryTable(new(User)).Filter("user_id", userId).Update(
			orm.Params{
				"activated": activated,
			},
		)
	}
	if err == nil {
		RemoveCachedUser(partnerId, userId)
	}
	return
}

func GetSubUsers(roleId int64,offset,limit int) (users []*User, err error) {
	sql := fmt.Sprintf(`select * from user where find_in_set(%d, role_ids) limit %d,%d`,roleId,offset,limit)
	o := models.GetDefaultDB()					
	_, err = o.Raw(sql).QueryRows(&users)
	return
}

func GetUserByPartnerIdAndApi(partnerId int64, isOpenApi int) (v *User, err error) {
	o := models.GetDefaultDB()
	v = &User{PartnerId:partnerId, IsOpenApi:isOpenApi}
	if err = o.Read(v, "PartnerId", "IsOpenApi"); err == nil {
		return v, nil
	}
	return nil, err
}
